package main

import (
	"fmt"
	"strings"
)

type Any interface{}

type Car struct {
	Model        string
	Manufacturer string
	BuildYear    int
}

type Cars []*Car

func (cs Cars) Process(f func(car *Car)) {
	for _, c := range cs {
		f(c)
	}
}

func (cs Cars) FindAll(f func(c *Car) bool) Cars {
	cars := make([]*Car, 0)
	for _, c := range cs {
		if f(c) {
			cars = append(cars, c)
		}
	}
	return cars
}

func (cs Cars) Map(f func(car *Car) Any) []Any {
	res := make([]Any, len(cs))
	ix := 0
	cs.Process(func(c *Car) {
		res[ix] = f(c)
		ix++
	})
	return res
}

func MakeSortedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {
	sortedCars := make(map[string]Cars)
	for _, m := range manufacturers {
		sortedCars[m] = make([]*Car, 0)
	}

	sortedCars["Default"] = make([]*Car, 0)

	appender := func(car *Car) {
		if _, ok := sortedCars[car.Manufacturer]; ok {
			sortedCars[car.Manufacturer] = append(sortedCars[car.Manufacturer], car)
		} else {
			sortedCars["Default"] = append(sortedCars["Default"], car)
		}
	}

	return appender, sortedCars
}

func (c Cars) String() string {
	str := "{"
	for _, car := range c {
		str += fmt.Sprintf("[%s, %s, %d]\n", car.Model, car.Manufacturer, car.BuildYear)
	}
	str = strings.TrimRight(str, "\n")
	str += "}\n"
	return str
}

func main() {
	// make some cars
	byd := &Car{"海豚", "BYD", 2023}
	byd2 := &Car{"汉", "BYD", 2022}
	lix := &Car{"理想One", "Li", 2021}
	xiao := &Car{"P5", "Xiaopeng", 2021}

	allCars := Cars{byd, byd2, lix, xiao}
	allNewByd := allCars.FindAll(func(car *Car) bool {
		return car.Manufacturer == "BYD" && car.BuildYear >= 2022
	})

	fmt.Printf("AllCars: %v\n", allCars)
	fmt.Printf("New Byd: %v\n", allNewByd)

	manufacturers := []string{"BYD", "Jeely", "Li", "Xiaopeng"}
	appender, sortCars := MakeSortedAppender(manufacturers)
	allCars.Process(appender)
	fmt.Println(sortCars)
}
